---
title: Guide Documents > Swagger Document
---
import { Tabs } from 'nextra/components'

import { EDITOR_EXAMPLES } from "../../../src/constants/EDITOR_EXAMPLES";
import { HyperLink } from "../../../src/components/basic/HyperLink";
import { List } from "../../../src/components/basic/List";
import { ListItem } from "../../../src/components/basic/ListItem";

## Outline
<Tabs items={["Bootstrap", "Configuration"]}>
  <Tabs.Tab>
```typescript filename="main.ts" showLineNumbers {8-9} copy
import { NestiaSwaggerComposer } from "@nestia/sdk";
import { INestApplication } from "@nestjs/common";
import { NestFactory } from "@nestjs/core";
import { SwaggerModule } from "@nestjs/swagger";

const main = async (): Promise<void> => {
  const app: INestApplication = await NestFactory.create(ApplicationModule);
  const document = await NestiaSwaggerComposer.document(app, {});
  SwaggerModule.setup("api", app, document as any);
  await app.listen(3_000);
};
main().catch(console.error);
```
  </Tabs.Tab>
  <Tabs.Tab>
```typescript filename="tsconfig.json" showLineNumbers
{
  "compilerOptions": {
    "strict": true,
    "plugins": [
      { "transform": "typia/lib/transform" },
      { "transform": "@nestia/core/lib/transform" },
      { "transform": "@nestia/sdk/lib/transform" }, // essential
    ],
  },
}
```
  </Tabs.Tab>
</Tabs>

If you want to build Swagger Document in runtime, compose it like above.

By the way, it needs plugin configuration on the `tsconfig.json` file.

<Tabs items={['Configuration', 'Build Script']} defaultIndex={1}>
  <Tabs.Tab>
```typescript filename="nestia.config.ts" showLineNumbers copy
import { INestiaConfig } from "@nestia/sdk";
import { NestFactory } from "@nestjs/core";
// import { FastifyAdapter } from "@nestjs/platform-fastify";

import { YourModule } from "./src/YourModule";

const NESTIA_CONFIG: INestiaConfig = {
  input: async () => {
    const app = await NestFactory.create(YourModule);
    // const app = await NestFactory.create(YourModule, new FastifyAdapter());
    // app.setGlobalPrefix("api");
    // app.enableVersioning({
    //     type: VersioningType.URI,
    //     prefix: "v",
    // })
    return app;
  },
  swagger: {
    openapi: "3.1",
    output: "dist/swagger.json",
    security: {
      bearer: {
        type: "apiKey",
        name: "Authorization",
        in: "header",
      },
    },
    servers: [
      {
        url: "http://localhost:3000",
        description: "Local Server",
      },
    ],
    beautify: true,
  },
};
export default NESTIA_CONFIG;
```
  </Tabs.Tab>
  <Tabs.Tab>
```bash filename="Terminal" showLineNumbers
# BUILD SWAGGER DOCUUMET ONLY
npx nestia swagger

# BUILD SWAGGER/SDK/E2E AT THE SAME TIME
npx nestia all
```
  </Tabs.Tab>
</Tabs>

Otherwise you want to generate a swagger file by CLI (Command Line Interface), configure `nestia.config.ts` file and run the `npx nestia swagger` command. Then, `@nestia/sdk` will analyze your NestJS backend server code, and generate `swagger.json` file.

When you want to build not only Swagger Document file, but also [SDK (Software Development Kit) library](./sdk) and [automated E2E (End-to-End) test functions](./e2e) at the same time, run `npx nestia all` command instead.




## Runtime Composition
### Bootstrap
```typescript filename="main.ts" showLineNumbers {8-17}
import { NestiaSwaggerComposer } from "@nestia/sdk";
import { INestApplication } from "@nestjs/common";
import { NestFactory } from "@nestjs/core";
import { SwaggerModule } from "@nestjs/swagger";

const main = async (): Promise<void> => {
  const app: INestApplication = await NestFactory.create(ApplicationModule);
  const document = await NestiaSwaggerComposer.document(app, {
    openapi: "3.1",
    servers: [
      {
        url: "http://localhost:3000",
        description: "Localhost"
      }
    ]
  });
  SwaggerModule.setup("api", app, document as any);
  await app.listen(3_000);
};
main().catch(console.error);
```

Call `NestiaSwaggerComposer.document()` function.

To compose Swagger Document in runtime and serve it through the Swagger UI in the NestJS application, import `NestiaSwaggerComposer` module from `@nestia/sdk` and call the `NestiaSwaggerComposer.document()` function with the `INestApplication` instance.

When you call the `NestiaSwaggerComposer.document()` function, `@nestia/sdk` will analyze your NestJS backed server code in the compilation level rapidly, and generate the Swagger Document object in the runtime. If you want to specify the OpenAPI version or server address(es), configure the second parameter of the `NestiaSwaggerComposer.document()` function.

After that, deliver the generated Swagger Document object to the `SwaggerModule.setup()` function of the `@nestjs/swagger` module. Then, the Swagger UI would be served in the `http://localhost:3000/api` address, and the `swagger.json` file would be placed on the http://localhost:3000/api-json location. Note that, as the NestJS core team and `SwaggerModule.setup()` function have not defined the exact OpenAPI document types, you've to cast the `document` object to `any` type.

### Plugin Configuration
```json filename="tsconfig.json" showLineNumbers
{
  "compilerOptions": {
    "strict": true,
    "plugins": [
      { "transform": "typia/lib/transform" },
      { "transform": "@nestia/core/lib/transform" },
      { "transform": "@nestia/sdk/lib/transform" }, // essential
    ],
  },
}
```

Configure plugin property of `tsconfig.json` file like above.

To activate the runtime swagger composer by `NestiaSwaggerComposer.document()` function, you have to configure the plugin on the `tsconfig.json` file. If you've not done it yet, open the `tsconfig.json` file and configure like above. If you don't do that, the runtime swagger composer cannot find any API operations, so that the Swagger Document would be empty.

<Tabs items={["Argument Specified", "Prompt Question"]}>
  <Tabs.Tab>
```bash filename="Terminal"
npm install --save-dev nestia@latest
npx nestia setup --runtime true
```
  </Tabs.Tab>
  <Tabs.Tab>
```bash filename="Terminal"
npm install --save-dev nestia@latest
npx nestia setup

----------------------------------------
 Nestia Setup Wizard
----------------------------------------
? Package Manager (Use arrow keys)
> npm
  pnpm
  yarn (berry is not supported)
? Transform Runtime Swagger (Use arrow keys)
> true
  false
```
  </Tabs.Tab>
</Tabs>

If you feel the `tsconfig.json` file configuration annoying, you can do it with CLI command of `nestia`. Just run the `npx nestia setup --runtime true` command, then the `tsconfig.json` file would be automatically configured with the plugin property. 

If you do not specify the `--runtime true` argument, so that run only the `npx nestia setup` command, the CLI prompt will ask you whether to configure the runtime argument or not. Answer as `yes` to configure it.




## File Generation
### Application Module
<Tabs items={[
  <code>nestia.config.ts</code>, 
  <code>INestiaConfig.ts</code>,
  <code>OpenApi.ISecuritySchema</code>,
]}>
  <Tabs.Tab>
```typescript copy filename="nestia.config.ts" showLineNumbers {18-35}
import { INestiaConfig } from "@nestia/sdk";
import { NestFactory } from "@nestjs/core";
// import { FastifyAdapter } from "@nestjs/platform-fastify";

import { YourModule } from "./src/YourModule";

const NESTIA_CONFIG: INestiaConfig = {
  input: async () => {
    const app = await NestFactory.create(YourModule);
    // const app = await NestFactory.create(YourModule, new FastifyAdapter());
    // app.setGlobalPrefix("api");
    // app.enableVersioning({
    //     type: VersioningType.URI,
    //     prefix: "v",
    // })
    return app;
  },
  swagger: {
    openapi: "3.1",
    output: "dist/swagger.json",
    security: {
      bearer: {
        type: "apiKey",
        name: "Authorization",
        in: "header",
      },
    },
    servers: [
      {
        url: "http://localhost:3000",
        description: "Local Server",
      },
    ],
    beautify: true,
  },
};
export default NESTIA_CONFIG;
```
  </Tabs.Tab>
  <Tabs.Tab>
```typescript filename="INestiaConfig.ts" showLineNumbers {10-15, 163-256}
import type { INestApplication } from "@nestjs/common";
import type { OpenApi } from "@samchon/openapi";

/**
 * Definition for the `nestia.config.ts` file.
 *
 * @author Jeongho Nam - https://github.com/samchon
 */
export interface INestiaConfig {
  /**
   * Building `swagger.json` is also possible.
   *
   * If not specified, you can't build the `swagger.json`.
   */
  swagger?: INestiaConfig.ISwaggerConfig;

  /**
   * Accessor of controller classes.
   *
   * You can specify it within two ways
   *
   *   - Asynchronous function returning `INestApplication` instance
   *   - Specify the path or directory of controller class files
   */
  input:
    | (() => Promise<INestApplication>)
    | INestiaConfig.IInput
    | string[]
    | string;

  /**
   * Output directory that SDK would be placed in.
   *
   * If not configured, you can't build the SDK library.
   */
  output?: string;

  /**
   * Target directory that SDK distribution files would be placed in.
   *
   * If you configure this property and runs `npx nestia sdk` command,
   * distribution environments for the SDK library would be generated.
   *
   * After the SDK library generation, move to the `distribute` directory,
   * and runs `npm publish` command, then you can share SDK library with
   * other client (frontend) developers.
   *
   * Recommend to use `"packages/api"` value.
   */
  distribute?: string;

  /**
   * Allow simulation mode.
   *
   * If you configure this property to be `true`, the SDK library would be contain
   * simulation mode. In the simulation mode, the SDK library would not communicate
   * with the real backend server, but just returns random mock-up data
   * with requestion data validation.
   *
   * For reference, random mock-up data would be generated by `typia.random<T>()`
   * function.
   *
   * @default false
   */
  simulate?: boolean;

  /**
   * Target directory that e2e test functions would be placed in.
   *
   * If you configure this property and runs `npx nestia e2e` command,
   * `@nestia/sdk` will analyze your NestJS backend server code, and
   * generates e2e test functions for every API endpoints.
   *
   * If not configured, you can't run `npx nestia e2e` command.
   */
  e2e?: string;

  /**
   * Whether to use propagation mode or not.
   *
   * If being configured, interaction functions of the SDK library would
   * perform the propagation mode. The propagation mode means that never
   * throwing exception even when status code is not 200 (or 201), but just
   * returning the {@link IPropagation} typed instance, which can specify its body
   * type through discriminated union determined by status code.
   *
   * @default false
   */
  propagate?: boolean;

  /**
   * Whether to clone DTO structures or not.
   *
   * If being configured, all of DTOs used in the backend server would be cloned
   * into the `structures` directory, and the SDK library would be refer to the
   * cloned DTOs instead of the original.
   *
   * @default false
   */
  clone?: boolean;

  /**
   * Whether to wrap DTO by primitive type.
   *
   * If you don't configure this property as `false`, all of DTOs in the
   * SDK library would be automatically wrapped by {@link Primitive} type.
   *
   * For refenrece, if a DTO type be capsuled by the {@link Primitive} type,
   * all of methods in the DTO type would be automatically erased. Also, if
   * the DTO has a `toJSON()` method, the DTO type would be automatically
   * converted to return type of the `toJSON()` method.
   *
   * @default true
   */
  primitive?: boolean;

  /**
   * Whether to assert parameter types or not.
   *
   * If you configure this property to be `true`, all of the function
   * parameters of SDK library would be checked through
   * [`typia.assert<T>()` function](https://typia.io/docs/validators/assert/).
   *
   * This option would make your SDK library compilation time a little bit slower,
   * but would enahcne the type safety even in the runtime level.
   *
   * @default false
   */
  assert?: boolean;

  /**
   * Whether to optimize JSON string conversion 10x faster or not.
   *
   * If you configure this property to be `true`, the SDK library would utilize the
   * [`typia.assertStringify<T>() function`](https://github.com/samchon/typia#enhanced-json)
   * to boost up JSON serialization speed and ensure type safety.
   *
   * This option would make your SDK library compilation time a little bit slower,
   * but would enhance JSON serialization speed 10x faster. Also, it can ensure type
   * safety even in the runtime level.
   *
   * @default false
   */
  json?: boolean;
}
export namespace INestiaConfig {
  /**
   * List of files or directories to include or exclude to specifying the NestJS
   * controllers.
   */
  export interface IInput {
    /**
     * List of files or directories containing the NestJS controller classes.
     */
    include: string[];

    /**
     * List of files or directories to be excluded.
     */
    exclude?: string[];
  }

  /**
   * Building `swagger.json` is also possible.
   */
  export interface ISwaggerConfig {
    /**
     * OpenAPI version.
     *
     * If you configure this property to be `2.0` or `3.0`, the newly generated
     * `swagger.json` file would follow the specified OpenAPI version. The newly
     * generated `swagger.json` file would be downgraded from the OpenAPI v3.1
     * specification by {@link OpenApi.downgrade} method.
     *
     * @default 3.1
     */
    openapi?: "2.0" | "3.0" | "3.1";
    
    /**
     * Output path of the `swagger.json`.
     *
     * If you've configured only directory, the file name would be the `swagger.json`.
     * Otherwise you've configured the full path with file name and extension, the
     * `swagger.json` file would be renamed to it.
     */
    output: string;

    /**
     * Whether to beautify JSON content or not.
     *
     * If you configure this property to be `true`, the `swagger.json` file would
     * be beautified with indentation (2 spaces) and line breaks. If you configure
     * numeric value instead, the indentation would be specified by the number.
     *
     * @default false
     */
    beautify?: boolean | number;

    /**
     * API information.
     *
     * If omitted, `package.json` content would be used instead.
     */
    info?: Partial<OpenApi.IDocument.IInfo>;

    /**
     * List of server addresses.
     */
    servers?: OpenApi.IServer[];

    /**
     * Security schemes.
     *
     * When generating `swagger.json` file through `nestia`, if your controllers or
     * theirs methods have a security key which is not enrolled in here property,
     * it would be an error.
     */
    security?: Record<string, OpenApi.ISecurityScheme>;

    /**
     * List of tag names with description.
     *
     * It is possible to omit this property or skip some tag name even if
     * the tag name is used in the API routes. In that case, the tag name
     * would be used without description.
     *
     * Of course, if you've written a comment like `@tag {name} {description}`,
     * you can entirely replace this property specification.
     */
    tags?: OpenApi.IDocument.ITag[];

    /**
     * Decompose query DTO.
     *
     * If you configure this property to be `true`, the query DTO would be decomposed
     * into individual query parameters per each property. Otherwise you set it to be
     * `false`, the query DTO would be one object type which contains all of query
     * parameters.
     *
     * @default false
     */
    decompose?: boolean;

    /**
     * Operation ID generator.
     *
     * @param props Properties of the API endpoint.
     * @returns Operation ID.
     */
    operationId?(props: {
      class: string;
      function: string;
      method: "HEAD" | "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
      path: string;
    }): string;
  }
}
```
  </Tabs.Tab>
  <Tabs.Tab>
```typescript filename="@samchon/openapi" showLineNumbers
/**
 * Security scheme of Swagger Documents.
 *
 * `ISecurityScheme` is a data structure representing content of
 * `securitySchemes` in `swagger.json` file. It is composed with 5 types of security
 * schemes as an union type like below.
 *
 * @reference https://swagger.io/specification/#security-scheme-object
 * @author Jeongho Nam - https://github.com/samchon
 */
export type ISecurityScheme =
  | ISecurityScheme.IHttpBasic
  | ISecurityScheme.IHttpBearer
  | ISecurityScheme.IApiKey
  | ISecurityScheme.IOpenId
  | ISecurityScheme.IOAuth2;
export namespace ISecurityScheme {
  export interface IHttpBasic {
    type: "http";
    scheme: "basic";
  }
  export interface IHttpBearer {
    type: "http";
    scheme: "bearer";
    bearerFormat?: string;
  }
  export interface IApiKey {
    type: "apiKey";
    in?: "header" | "query" | "cookie";
    name?: string;
  }

  export interface IOpenId {
    type: "openIdConnect";
    openIdConnectUrl: string;
  }

  export interface IOAuth2 {
    type: "oauth2";
    flows: IOAuth2.IFlowSet;
    description?: string;
  }
  export namespace IOAuth2 {
    export interface IFlowSet {
      authorizationCode?: IFlow;
      implicit?: Omit<IFlow, "tokenUrl">;
      password?: Omit<IFlow, "authorizationUrl">;
      clientCredentials?: Omit<IFlow, "authorizationUrl">;
    }
    export interface IFlow {
      authorizationUrl: string;
      tokenUrl: string;
      refreshUrl: string;
      scopes?: Record<string, string>;
    }
  }
}
```
  </Tabs.Tab>
</Tabs>

Make `nestia.config.ts` file and run `npx nestia swagger` command.

At first, create `nestia.config.ts` file through `npx nestia init` command. It would be placed on the top level directory of your NestJS backend project. For reference, `tsconfig.json` file also must be placed in the top level directory, too. After creation, configure the `nestia.config.ts` file referencing above example code and type definition.

At least, you've to configure those two properties:

  - `input`: Accessor of controller classes
  - `swagger.output`: Path of `swagger.json` file

When you've completed above configuration, just run `npx nestia swagger` command. Then, `swagger.json` file would be newly generated, and placed into the `$config.swagger.output` directory following your `nestia.config.ts` configuration.

### Multiple Files Generation
```typescript filename="nestia.config.ts" showLineNumbers
import { INestiaConfig } from "@nestia/sdk";
import { NestFactory } from "@nestjs/core";

import { AppModule } from "./src/modules/AppModule";
import { BbsModule } from "./src/modules/BbsModule";
import { CommonModule } from "./src/modules/CommonModule";

export const NESTIA_CONFIGURATIONS: INestiaConfig[] = [
  {
    input: () => NestFactory.create(AppModule),
    swagger: {
      output: "swagger.json",
      security: {
        bearer: {
          type: "apiKey",
        },
      },
    },
  },
  {
    input: () => NestFactory.create(BbsModule),
    swagger: {
      output: "bbs.swagger.json",
      security: {
        bearer: {
          type: "apiKey",
        },
      },
    },
  },
  {
    input: () => NestFactory.create(CommonModule),
    swagger: {
      output: "common.swagger.json",
      security: {
        bearer: {
          type: "apiKey",
        },
      },
    },
  },
];
export default NESTIA_CONFIGURATIONS;
```

You can build multiple Swagger Document files.

Just configure an array of `INestiaConfig` instances like above example code. 

Then, `@nestia/sdk` will generate multiple Swagger Document files following the configurations.

### Additional Properties
Additionally, you can configure the `swagger` property in the `nestia.config.ts` file.

  - `swagger.openapi`: OpenAPI version specification.
    - `"2.0"`
    - `"3.0"`
    - `"3.1"` *(default)*
  - `swagger.beautify`: Whether to beautify JSON content or not. 
  - `swagger.info`: API information. If not configured, `package.json` content be utilized instead.
  - `swagger.servers`: List of server addresses.
  - `swagger.security`: Security schemes.
  - `swagger.tags`: List of tag names with description.
  - `swagger.decompose`: Whether to decompose query DTO as individual parameters.
  - `swagger.operationId`: Operation ID generator.

For reference, if you do not configure `swagger.info` property or omit some members of the information instance, `@nestia/sdk` will utilize your `package.json` file content instead. For example, if you omit the `swagger.info.version`, your `package.json` file's `version` property would be written instead.

Also, whether you configure `swagger.openapi` version or not, the newly generated `swagger.file` starts from the [OpenAPI v3.1 specification](https://github.com/samchon/openapi/blob/master/src/OpenApi.ts) emended by [`@samchon/openapi`](https://github.com/samchon/openapi). If your target OpenAPI version is lower than v3.1, `@nestia/sdk` just downgrades the newly generated OpenAPI v3.1 content by calling [`OpenApi.downgrade()`](https://github.com/samchon/openapi/blob/master/src/OpenApi.ts) function.

<details>
<summary> See detailed options: </summary>
<br/>
```typescript filename="INestiaConfig.ts" showLineNumbers {15-108}
export namespace INestiaConfig {
  /**
   * Building `swagger.json` is also possible.
   */
  export interface ISwaggerConfig {
    /**
     * Output path of the `swagger.json`.
     *
     * If you've configured only directory, the file name would be the `swagger.json`.
     * Otherwise you've configured the full path with file name and extension, the
     * `swagger.json` file would be renamed to it.
     */
    output: string;

    /**
     * OpenAPI version.
     *
     * If you configure this property to be `2.0` or `3.0`, the newly generated
     * `swagger.json` file would follow the specified OpenAPI version. The newly
     * generated `swagger.json` file would be downgraded from the OpenAPI v3.1
     * specification by {@link OpenApi.downgrade} method.
     *
     * @default 3.1
     */
    openapi?: "2.0" | "3.0" | "3.1";

    /**
     * Whether to beautify JSON content or not.
     *
     * If you configure this property to be `true`, the `swagger.json` file would
     * be beautified with indentation (2 spaces) and line breaks. If you configure
     * numeric value instead, the indentation would be specified by the number.
     *
     * @default false
     */
    beautify?: boolean | number;

    /**
     * API information.
     *
     * If omitted, `package.json` content would be used instead.
     */
    info?: Partial<OpenApi.IDocument.IInfo>;

    /**
     * List of server addresses.
     */
    servers?: OpenApi.IServer[];

    /**
     * Security schemes.
     *
     * When generating `swagger.json` file through `nestia`, if your controllers or
     * theirs methods have a security key which is not enrolled in here property,
     * it would be an error.
     */
    security?: Record<string, OpenApi.ISecurityScheme>;

    /**
     * List of tag names with description.
     *
     * It is possible to omit this property or skip some tag name even if
     * the tag name is used in the API routes. In that case, the tag name
     * would be used without description.
     *
     * Of course, if you've written a comment like `@tag {name} {description}`,
     * you can entirely replace this property specification.
     */
    tags?: OpenApi.IDocument.ITag[];

    /**
     * Decompose query DTO.
     *
     * If you configure this property to be `true`, the query DTO would be decomposed
     * into individual query parameters per each property. Otherwise you set it to be
     * `false`, the query DTO would be one object type which contains all of query
     * parameters.
     *
     * @default false
     */
    decompose?: boolean;

    /**
     * Operation ID generator.
     *
     * @param props Properties of the API endpoint.
     * @returns Operation ID.
     */
    operationId?(props: {
      class: string;
      function: string;
      method: "HEAD" | "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
      path: string;
    }): string;
  }
}
```

</details>

### CLI Arguments
```bash filename="Terminal"
npx nestia swagger
npx nestia swagger --config nestia2.config.ts
npx nestia swagger --project tsconfig2.json
npx nestia swagger --config nestia3.config.ts --project tsconfig3.tsconfig.json
```

If you have a special configuration file that its file name is not `nestia.config.ts` or the configuration file is not placed on the root directory of the project, you can specify it with `--config` option like `npx nestia swagger --config another.config.ts`. 

Also, if you have a special `tsconfig.json` file or the project file is not located in the root directory of the project, you can specify it with `--project` argument like `npx nestia swagger --project another.tsconfig.json`, too.




## Special Tags
### NestJS Decorators
Swagger generator for `@nestia/sdk` supports some NestJS decorators. Here is the list of them. 

  - `@nestjs/common`
    - `@Header()`
    - `@HttpCode()`
    - `@Version()`
  - `@nestjs/swagger`
    - `@ApiBasicAuth()`
    - `@ApiBearerAuth()`
    - `@ApiOAuth2()`
    - `@ApiSecurity()`
    - `@ApiTags()`
    - `@ApiExtension()`
  - `@nestia/core`
    - `@TypedException()`
    - `@SwaggerExample.Parameter()`
    - `@SwaggerExample.Response()`

### Controller Methods
Swagger generator `@nestia/sdk` supports three type of comment tags for controller methods:

  - Hiding
    - `@deprecated`: mark as `deprecated`
    - `@internal`: hide, never be shown
    - `@hidden`: hide, never be shown
    - `@ignore`: hide, never be shown, even in the SDK side
  - Labeling
    - `@summary` : short description of endpoint
    - `@tag {name} {description?}`: grouppig with description
    - `@operationId {value}`: manual operation ID
  - Security
    - `@security {key}`: security scheme key
    - `@security {key} {...scopes}`: +scopes for OAuth2 type

At first, `@internal`, `@hidden` and `@ignore` tags are used to hide the controller method from the Swagger Documents. When you use one of them, the controller method would not be written in the `swagger.json` file. Otherwise, the `@deprecated` tag is used to mark the controller method as deprecated. When you use it, Swagger Editor will show the deprecated message about the route method like below.

Also, the `@summary` tag is used to write short description of the endpoint. By the way, the `@summary` tag can be replaced by writing top sentence ends with `.` symbol. The other one, `@tag {name} {description?}` tag is used for only grouping. If you fill the `description` part, it would be shown in the Swagger-UI.

The last one, `@security` is a tag for security scheme. It specifies target security scheme by writing its key like `@security {key}`. If target scheme type is OAuth2, and it has configured scopes, you can specify the scopes by writing scopes at the backward like `@security {key} read write`. 

For reference, target security schemes must be configured in the `nestia.config.ts` file. If you use `@security` tag that is not configured in the `nestia.config.ts` file, it would be an error. Also, if you've configured `@nestia/swagger` security decorator like `@ApiSecurity`, `@nestia/sdk` also can recognize it too.

<Tabs items={[
  'Controller', 
  'Swagger Documents', 
  <code>nestia.config.ts</code>,
  <code>OpenApi.ISecurityScheme</code>,
]}>
  <Tabs.Tab>
```typescript filename="Controller" showLineNumbers {17-20, 35, 46-49, 66, 68}
import { TypedBody, TypedParam, TypedRoute } from "@nestia/core";
import { Controller } from "@nestjs/common";
import { ApiSecurity } from "@nestjs/swagger";
import typia, { tags } from "typia";

import { IBbsArticle } from "@api/lib/structures/IBbsArticle";

@Controller("bbs/articles/:section")
export class BbsArticlesController {
  /**
   * Would be shown without any mark.
   *
   * @param section Section code
   * @param input Content to store
   * @returns Newly archived article
   *
   * @tag public Some description describing public group...
   * @summary Public API
   * @security bearer
   * @security oauth2 read write
   */
  @TypedRoute.Post()
  public async store(
    @TypedParam("section") section: string,
    @TypedBody() input: IBbsArticle.IStore,
  ): Promise<IBbsArticle> {
    return {
      ...typia.random<IBbsArticle>(),
      ...input,
      section,
    };
  }

  /**
   * Deprecated API.
   *
   * Would be marked as "deprecated".
   *
   * For reference, top sentence "Deprecated API." can replace the `@summary` tag.
   *
   * @param section Section code
   * @param id Target article ID
   * @param input Content to update
   * @returns Updated content
   *
   * @deprecated
   * @operationId updateArticle
   * @security basic
   * @security bearer
   */
  @TypedRoute.Put(":id")
  public async update(
    @TypedParam("section") section: string,
    @TypedParam("id") id: string & tags.Format<"uuid">,
    @TypedBody() input: IBbsArticle.IStore,
  ): Promise<IBbsArticle> {
    return {
      ...typia.random<IBbsArticle>(),
      ...input,
      id,
      section,
    };
  }

  /**
   * Would not be shown.
   *
   * @internal
   */
  @ApiSecurity("custom") // LEGACY DECORATOR ALSO CAN BE USED
  @TypedRoute.Delete(":id")
  public erase(
    @TypedParam("section") section: string,
    @TypedParam("id") id: string & tags.Format<"uuid">,
  ): void {
    section;
    id;
  }
}
```
  </Tabs.Tab>
  <Tabs.Tab>
```json filename="swagger.json" showLineNumbers {20-22, 60-70, 75, 77, 124-131, 266-271}
{
  "openapi": "3.1.0",
  "servers": [
    {
      "url": "https://github.com/samchon/nestia",
      "description": "insert your server url"
    }
  ],
  "info": {
    "version": "3.0.3",
    "title": "@nestia/test",
    "description": "Test program of Nestia",
    "license": {
      "name": "MIT"
    }
  },
  "paths": {
    "/bbs/articles/{section}": {
      "post": {
        "tags": [
          "public"
        ],
        "operationId": "BbsArticlesController.store",
        "parameters": [
          {
            "name": "section",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "description": "Section code",
            "required": true
          }
        ],
        "requestBody": {
          "description": "Content to store",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IBbsArticle.IStore"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Newly archived article",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IBbsArticle"
                }
              }
            }
          }
        },
        "summary": "Public API",
        "description": "Would be shown without any mark.",
        "security": [
          {
            "bearer": []
          },
          {
            "oauth2": [
              "read",
              "write"
            ]
          }
        ]
      }
    },
    "/bbs/articles/{section}/{id}": {
      "put": {
        "deprecated": true,
        "tags": [],
        "operationId": "updateArticle",
        "parameters": [
          {
            "name": "section",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "description": "Section code",
            "required": true
          },
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Target article ID",
            "required": true
          }
        ],
        "requestBody": {
          "description": "Content to update",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IBbsArticle.IStore"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Updated content",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IBbsArticle"
                }
              }
            }
          }
        },
        "summary": "Deprecated API",
        "description": "Deprecated API.\n\nWould be marked as \"deprecated\".\n\nFor reference, top sentence \"Deprecated API.\" can replace the `@summary` tag.",
        "security": [
          {
            "basic": []
          },
          {
            "bearer": []
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "IBbsArticle.IStore": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 3,
            "maxLength": 50
          },
          "body": {
            "type": "string"
          },
          "files": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IAttachmentFile"
            }
          }
        },
        "required": [
          "title",
          "body",
          "files"
        ]
      },
      "IAttachmentFile": {
        "type": "object",
        "properties": {
          "name": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "string",
                "maxLength": 255
              }
            ]
          },
          "extension": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 8
              }
            ]
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        },
        "required": [
          "name",
          "extension",
          "url"
        ]
      },
      "IBbsArticle": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "section": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "title": {
            "type": "string",
            "minLength": 3,
            "maxLength": 50
          },
          "body": {
            "type": "string"
          },
          "files": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IAttachmentFile"
            }
          }
        },
        "required": [
          "id",
          "section",
          "created_at",
          "title",
          "body",
          "files"
        ]
      }
    },
    "securitySchemes": {
      "basic": {
        "type": "http",
        "scheme": "basic"
      },
      "bearer": {
        "type": "http",
        "scheme": "bearer"
      },
      "oauth2": {
        "type": "oauth2",
        "flows": {
          "implicit": {
            "authorizationUrl": "https://example.com/api/oauth/dialog",
            "refreshUrl": "https://example.com/api/oauth/refresh",
            "scopes": {
              "read": "read authority",
              "write": "write authority"
            }
          }
        }
      },
      "custom": {
        "type": "apiKey",
        "in": "header",
        "name": "Authorization"
      }
    }
  },
  "tags": [
    {
      "name": "public",
      "description": "Some description describing public group..."
    }
  ],
  "x-samchon-emended": true
}
```
  </Tabs.Tab>
  <Tabs.Tab>
```typescript filename="nestia.config.ts" showLineNumbers {6-51}
import type { INestiaConfig } from "@nestia/sdk";

export const NESTIA_CONFIG: INestiaConfig = {
  input: ["src/controllers"],
  output: "src/api",
  swagger: {
    output: "swagger.json",
    beautify: true,
    operationId: (props) => `${props.class}.${props.function}`,
    security: {
      //----
      // YOU CAN CHOOSE ANY SECURITY SCHEMES LIKE
      //----
      // @security basic
      // @security bearer
      // @security oauth2 read write
      // @security custom
      basic: {
        type: "http",
        scheme: "basic",
      },
      bearer: {
        type: "http",
        scheme: "bearer",
      },
      oauth2: {
        type: "oauth2",
        flows: {
          implicit: {
            authorizationUrl: "https://example.com/api/oauth/dialog",
            refreshUrl: "https://example.com/api/oauth/refresh",
            scopes: {
              //----
              // YOU CAN CHOOSE ANY SCOPES
              //----
              // (@security oauth2 read write) -> BOTH OF THEM
              // (@security oauth2 read) -> ONE OF THEM
              // (@security oauth) -> NOTHING
              read: "read authority",
              write: "write authority",
            },
          },
        },
      },
      custom: {
        type: "apiKey",
        in: "header",
        name: "Authorization",
      },
    },
  },
};
export default NESTIA_CONFIG;
```
  </Tabs.Tab>
  <Tabs.Tab>
```typescript filename="@samchon/openapi" showLineNumbers
/**
 * Security scheme of Swagger Documents.
 *
 * `OpenApi.ISecurityScheme` is a data structure representing content of
 * `securitySchemes` in `swagger.json` file. It is composed with 5 types of security
 * schemes as an union type like below.
 *
 * @reference https://swagger.io/specification/#security-scheme-object
 * @author Jeongho Nam - https://github.com/samchon
 */
export type ISecurityScheme =
  | ISecurityScheme.IHttpBasic
  | ISecurityScheme.IHttpBearer
  | ISecurityScheme.IApiKey
  | ISecurityScheme.IOpenId
  | ISecurityScheme.IOAuth2;
export namespace ISecurityScheme {
  export interface IHttpBasic {
    type: "http";
    scheme: "basic";
  }
  export interface IHttpBearer {
    type: "http";
    scheme: "bearer";
    bearerFormat?: string;
  }
  export interface IApiKey {
    type: "apiKey";
    in?: "header" | "query" | "cookie";
    name?: string;
  }

  export interface IOpenId {
    type: "openIdConnect";
    openIdConnectUrl: string;
  }

  export interface IOAuth2 {
    type: "oauth2";
    flows: IOAuth2.IFlowSet;
    description?: string;
  }
  export namespace IOAuth2 {
    export interface IFlowSet {
      authorizationCode?: IFlow;
      implicit?: Omit<IFlow, "tokenUrl">;
      password?: Omit<IFlow, "authorizationUrl">;
      clientCredentials?: Omit<IFlow, "authorizationUrl">;
    }
    export interface IFlow {
      authorizationUrl: string;
      tokenUrl: string;
      refreshUrl: string;
      scopes?: Record<string, string>;
    }
  }
}
```
  </Tabs.Tab>
</Tabs>

![Swagger Editor](/images/swagger-tags.png)




### DTO Properties
https://swagger.io/docs/specification/data-models/data-types/

You can utilize comments and tags to construct special fields of JSON schema.

If you write any comment on a property, it would fill the `IJsonSchema.description` value. When you utilize [Special tags of `typia`](https://typia.io/docs/typia/validators/tags), they would be placed into the proper properties of `IJsonSchema`. Below is the list of supported type and comment tags in the `@nestia/sdk`.

Also, such type and comment tags of DTO properties can be used to enhance validation logic of `@nestia/core` library. Especially, [`@TypedBody.${method}()`](../core/TypedBody#tags), [`@TypedParam()`](../core/TypedParam#tags), [`@TypedRoute()`](../core/TypedRoute#tags) and [`@TypedQuery()`](../core/TypedQuery#tags) functions can use those tags for additional validation.

Let's see how those type and comment tags work with example code.

  - number
    - `number & Type<{keyword}>`
      - `int32`
      - `uint32`
      - `uint64`
      - `int64`
      - `float`
      - `double`
    - `number & Minimum<{number}>`
    - `number & Maximum<{number}>`
    - `number & ExclusiveMaximum<{number}>`
    - `number & ExclusiveMinimum<{number}>`
    - `number & MultipleOf<{number}>`
  - bigint
    - `bigint & Type<{keyword}>`
      - `int64`
      - `uint64`
    - `bigint & Minimum<{bigint}>`
    - `bigint & Maximum<{bigint}>`
    - `bigint & ExclusiveMaximum<{bigint}>`
    - `bigint & ExclusiveMinimum<{bigint}>`
    - `bigint & MultipleOf<{bigint}>`
  - string
    - `string & MinLength<{number}>`
    - `string & MaxLength<{number}>`
    - `string & Pattern<{regex}>`
    - `string & Format<{keyword}>`
      - `email`
      - `uuid`
      - `ipv4`
      - `ipv6`
      - `url`
      - `date`: YYYY-MM-DD
      - `date-time`: `Date.toISOString()`

<Tabs items={[
  <code>IBbsArticle.ts</code>, 
  <code>swagger.json</code>
]}>
  <Tabs.Tab>
```typescript copy filename="SpecialTag.ts" showLineNumbers
export interface SpecialTag {
  /**
   * Deprecated tags are just used for marking.
   *
   * @title Unsigned integer
   * @deprecated
   */
  type: number & tags.Type<"uint32">;

  /**
   * Internal tagged property never be shown in JSON schema.
   *
   * It even doesn't be shown in other `typia` functions like `assert<T>()`.
   *
   * @internal
   */
  internal: number[];

  /**
   * Hidden tagged property never be shown in JSON schema.
   *
   * However, it would be shown in other `typia` functions like `stringify<T>()`.
   *
   * @hidden
   */
  hidden: boolean;

  /**
   * You can limit the range of number.
   *
   * Also, you can configure `default` property by comment tag.
   *
   * @default 30
   */
  number?: number & tags.ExclusiveMinimum<19> & tags.Maximum<100>;

  /**
   * You can limit the length of string.
   */
  string: string & tags.MinLength<3>;

  /**
   * You can limit the pattern of string.
   */
  pattern: string & tags.Pattern<"^[a-z]+$">;

  /**
   * You can limit the format of string.
   */
  format: null | (string & tags.Format<"date-time">);

  /**
   * You also can perform union type in type tags.
   */
  ip: string & (tags.Format<"ipv4"> | tags.Format<"ipv6">);

  /**
   * In the Array case, only type tags can limit elements' type.
   */
  array: Array<string & tags.Format<"uuid">> &
    tags.MinItems<3> &
    tags.MaxItems<100>;
}
```
  </Tabs.Tab>
  <Tabs.Tab>
```json filename="swagger.json" showLineNumbers {6, 9, 14-17, 22, 27, 33, 46, 51, 62, 64-65}
{
  "SpecialTag": {
    "type": "object",
    "properties": {
      "type": {
        "deprecated": true,
        "title": "Unsigned integer",
        "description": "Deprecated tags are just used for marking.",
        "type": "integer"
      },
      "number": {
        "description": "You can limit the range of number.\n\nAlso, you can configure `default` property by comment tag.",
        "type": "number",
        "minimum": 19,
        "exclusiveMinimum": true,
        "maximum": 100,
        "default": 30
      },
      "string": {
        "description": "You can limit the length of string.",
        "type": "string",
        "minLength": 3
      },
      "pattern": {
        "description": "You can limit the pattern of string.",
        "type": "string",
        "pattern": "^[a-z]+$"
      },
      "format": {
        "oneOf": [
          {
            "type": "string",
            "format": "date-time",
          },
          {
            "type": "null",
          }
        ],
        "description": "You can limit the format of string.",
      },
      "ip": {
        "oneOf": [
          {
            "description": "You also can perform union type in type tags.",
            "type": "string",
            "format": "ipv4"
          },
          {
            "description": "You also can perform union type in type tags.",
            "type": "string",
            "format": "ipv6"
          }
        ],
        "description": "You also can perform union type in type tags."
      },
      "array": {
        "description": "In the Array case, only type tags can limit elements' type.",
        "type": "array",
        "items": {
          "description": "In the Array case, only type tags can limit elements' type.",
          "type": "string",
          "format": "uuid"
        },
        "maxItems": 100,
        "minItems": 3
      }
    },
    "required": [
      "type",
      "string",
      "pattern",
      "format",
      "ip",
      "array"
    ]
  }
}
```
  </Tabs.Tab>
  <Tabs.Tab>
```typescript filename="nestia.config.ts" showLineNumbers
/**
 * Security schema of Swagger Documents.
 *
 * `ISecurityScheme` is a data structure representing content of
 * `securitySchemes` in `swagger.json` file. It is composed with 5 types of security
 * schemes as an union type like below.
 *
 * @reference https://swagger.io/specification/#security-scheme-object
 * @author Jeongho Nam - https://github.com/samchon
 */
export type ISecurityScheme =
  | ISecurityScheme.IHttpBasic
  | ISecurityScheme.IHttpBearer
  | ISecurityScheme.IApiKey
  | ISecurityScheme.IOpenId
  | ISecurityScheme.IOAuth2;
export namespace ISecurityScheme {
  export interface IHttpBasic {
    type: "http";
    scheme: "basic";
  }
  export interface IHttpBearer {
    type: "http";
    scheme: "bearer";
    bearerFormat?: string;
  }
  export interface IApiKey {
    type: "apiKey";

    /**
     * @default header
     */
    in?: "header" | "query" | "cookie";

    /**
     * @default Authorization
     */
    name?: string;
  }

  export interface IOpenId {
    type: "openIdConnect";
    openIdConnectUrl: string;
  }

  export interface IOAuth2 {
    type: "oauth2";
    flows: IOAuth2.IFlowSet;
    description?: string;
  }
  export namespace IOAuth2 {
    export interface IFlowSet {
      authorizationCode?: IFlow;
      implicit?: Omit<IFlow, "tokenUrl">;
      password?: Omit<IFlow, "authorizationUrl">;
      clientCredentials?: Omit<IFlow, "authorizationUrl">;
    }
    export interface IFlow {
      authorizationUrl: string;
      tokenUrl: string;
      refreshUrl: string;
      scopes?: Record<string, string>;
    }
  }
}
```
  </Tabs.Tab>
</Tabs>




## Customization
[Typia > JSON schema > Customization](https://typia.io/docs/json/schema/#customization)

If what you want is not just filling special properties of JSON schema spec, but to adding custom properties into the JSON schema definition, you can accomlish it with `typia` feature. Define a type based on `typia.tags.TagBase` or `typia.tags.JsonSchemaPlugin`, and specify the `schema` property type as you want.

For reference, the custom property must be started with x- prefix. It's a rule of JSON schema.

<Tabs items={['TypeScript Source Code', 'Compiled JavaScript File']}>
  <Tabs.Tab>
```typescript copy filename="examples/src/json-schema-custom.ts" copy showLineNumbers {7-9, 13, 17-18}
import typia, { tags } from "typia";
 
type Monetary<Value extends string> = tags.TagBase<{
  target: "number";
  kind: "monetary";
  value: Value;
  schema: {
    "x-monetary": Value;
  };
}>;

type Placeholder<Value extends string> = tags.JsonSchemaPlugin<{
  "x-placeholder": Value;
}>;

interface IAccount {
  code: string & Placeholder<"Write you account code please">;
  balance: number & Monetary<"dollar">;
};
typia.json.application<[IAccount]>();
```
  </Tabs.Tab>
  <Tabs.Tab>
```javascript copy filename="examples/bin/json-schema-custom.js" showLineNumbers {10, 14}
({
  version: "3.1",
  components: {
    schemas: {
      IAccount: {
        type: "object",
        properties: {
          code: {
            type: "string",
            "x-placeholder": "Write you account code please",
          },
          balance: {
            type: "number",
            "x-monetary": "dollar",
          },
        },
        required: ["code", "balance"],
      },
    },
  },
  schemas: [
    {
      $ref: "#/components/schemas/IAccount",
    },
  ],
});
```
  </Tabs.Tab>
</Tabs>

Otherwise you wanna customize the swagger data, utilize the `@SwaggerCustomizer()` decorator.

As you can see from the below example code, callback function defined in the `@SwaggerCustomizer()` decorator is changing the swagger data, because it is called when the `npx nestia swagger` command being executed. Furthermore, it is possible to add plugin property starting with `x-` characters.

Also, this `@SwaggerCustomizer()` decorator is especially useful when defining an authentication decorator. Developing the authentication logic in the decorator function, apply the `@SwaggerCustomizer()` with `OpenApi.IOperation.security` property. Then whenever the decorator function is called, the security scheme would be added into the swagger data.

<Tabs items={[
    <code>@nestia/core</code>, 
    <code>MyCustomController.ts</code>, 
    <code>ShoppingSellerAuth.ts</code>
  ]} 
  defaultIndex={2}>
  <Tabs.Tab>
```typescript filename="@nestia/core" showLineNumbers
export function SwaggerCustomizer(
  closure: (props: SwaggerCustomizer.IProps) => unknown,
): MethodDecorator;
export namespace SwaggerCustomizer {
  export interface IProps {
    swagger: OpenApi.IDocument;
    method: string;
    path: string;
    route: OpenApi.IOperation;
    at(func: Function): ISwaggerEndpoint | undefined;
    get(accessor: IAccessor): OpenApi.IOperation | undefined;
  }
  export interface IAccessor {
    path: string;
    method: string;
  }
  export interface ISwaggerEndpoint extends IAccessor {
    route: OpenApi.IOperation;
  }
}
```
  </Tabs.Tab>
  <Tabs.Tab>
```typescript filename="CustomController.ts" showLineNumbers {7-18}
import { SwaggerCustomizer, TypedParam, TypedRoute } from "@nestia/core";
import { Controller } from "@nestjs/common";
import { tags } from "typia";

@Controller("custom")
export class CustomController {
  @SwaggerCustomizer((props: SwaggerCustomizer.IProps) => {
    props.swagger.openapi = "3.1.99";
    props.route.description = "This is a custom description";
    (props.route as any)["x-special-symbol"] = "Something Special";

    const neighbor = props.at(CustomController.prototype.normal);
    if (neighbor) {
      neighbor.description = "That is the normal description";
      (neighbor.route as any)["x-special-symbol"] = "Something Normal";
    }
  })
  @TypedRoute.Get(":key/customize")
  public customize(@TypedParam("key") key: number): string {
    return key.toString();
  }

  @TypedRoute.Get(":id/normal")
  public normal(@TypedParam("id") id: string & tags.Format<"uuid">): string {
    return id.toString();
  }
}
```
  </Tabs.Tab>
  <Tabs.Tab>
```typescript filename="ShoppingSellerAuth.ts" showLineNumbers {14-19}
import { ExecutionContext, createParamDecorator } from "@nestjs/common";
import { Singleton } from "tstl";

import { ShoppingSellerProvider } from "../providers/shoppings/actors/ShoppingSellerProvider";
import { SwaggerCustomizer } from "@nestia/core";

export const ShoppingSellerAuth =
  (): ParameterDecorator =>
  (
    target: Object,
    propertyKey: string | symbol | undefined,
    parameterIndex: number
  ): void => {
    SwaggerCustomizer((props) => {
      props.route.security ??= [];
      props.route.security.push({
        bearer: [],
      });
    })(target, propertyKey as string, undefined!);
    singleton.get()(target, propertyKey, parameterIndex);
  };

const singleton = new Singleton(() =>
  createParamDecorator(async (_0: any, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    return ShoppingSellerProvider.authorize(request);
  })()
);
```
  </Tabs.Tab>
</Tabs>




## Distribution
You can choose two options for `swagger.json` file distribution.

The 1st is publishing the `swagger.json` file in a public repo, and showing it through [`@nestia/editor`](/docs/editor) like below:

{<List>
  {EDITOR_EXAMPLES.map((example) => (
    <ListItem>
      <HyperLink 
        href={`/editor/?url=${encodeURIComponent(example.swagger)}&simulate=true&e2e=true`} 
        target="_blank">
        {example.title}
      </HyperLink>
    </ListItem>
  ))}
</List>}

The 2nd way is to hosting the `swagger.json` file in the NestJS backend server.

Read below example code, and follow it on yours:

<Tabs items={["Runtime", "File Generated"]}>
  <Tabs.Tab>
```typescript filename="main.ts" showLineNumbers copy
import { NestiaSwaggerComposer } from "@nestia/sdk";
import { INestApplication } from "@nestjs/common";
import { NestFactory } from "@nestjs/core";
import { SwaggerModule } from "@nestjs/swagger";

const main = async (): Promise<void> => {
  const app: INestApplication = await NestFactory.create(ApplicationModule);
  const document = await NestiaSwaggerComposer.document(app, {});
  SwaggerModule.setup("api", app, document as any);

  await app.listen(3_000);
};
main().catch(console.error);
```
  </Tabs.Tab>
  <Tabs.Tab>
```typescript filename="main.ts" showLineNumbers copy
import { NestFactory } from "@nestjs/core";
import { SwaggerModule } from "@nestjs/swagger";
import fs from "fs";

const main = async (): Promise<void> => {
  const app = await NestFactory.create(ApplicationModule);
  const docs = require("...write swagger.json path");
  docs.servers = [{ url: "write your server URL" }];
  SwaggerModule.setup("swagger", app, docs);

  await app.listen(8080);
}
main().catch(console.error);
```
  </Tabs.Tab>
</Tabs>
